#include "aerIntersection.hpp"


namespace aer {


IntersectionResult intersectPlaneAABB(const glm::vec4 &plane, const BoundingBox &aabb)
{
  // Projection interval extent of the box to the plane
  const Vector3 &n = plane.xyz();
  float extent = glm::dot( aabb.getScale(), glm::abs(n));
  
  // Distance of box center from plane
  float signedDistance = glm::dot( n, aabb.getCenter()) + plane.w;//
   
  if ((signedDistance - extent) > 0.0f) {
    return INSIDE;
  }
  if ((signedDistance + extent) < 0.0f) {
    return OUTSIDE;
  }
  
  // intersects when signedDistance is in [-extent, extent]
  return INTERSECTING;
}


IntersectionResult intersectFrustumAABB(const Vector4 planes[Frustum::kNumPlane], 
                                          const BoundingBox &aabb)
{
  /// Improvement : 
  /// # use same dot product result for Near / Far plane (last ones)
  /// # use the octant test
    
  bool bIntersect = false;
  
  for (U8 i=0; i<Frustum::kNumPlane; ++i)
  {
    IntersectionResult result = intersectPlaneAABB( planes[i], aabb);
    
    if (result == OUTSIDE) return OUTSIDE;    
    if (result == INTERSECTING) bIntersect = true;
  }
  
  if (bIntersect) {
    return INTERSECTING;
  }
  
  return INSIDE;
}


IntersectionResult intersectFrustumAABB(const glm::vec4 planes[Frustum::kNumPlane], 
                                          const BoundingBox &aabb,
                                          U8 *pLastId)
{
  /// Use the plane-coherency test :
  /// Give a pointer index to the first plane to test 
  /// (used to store the failed plane)
    
  U8 planeId = *pLastId;
  bool bIntersect = false;
  
  for (U8 i=0u; i<Frustum::kNumPlane; ++i)
  {
    IntersectionResult result = intersectPlaneAABB( planes[planeId], aabb);
    
    if (result == OUTSIDE) 
    {
      *pLastId = planeId;
      return OUTSIDE;
    }
    
    if (result == INTERSECTING) { bIntersect = true; }
    
    planeId = (planeId+1) % Frustum::kNumPlane;
  }
  *pLastId = 0;
  
  if (bIntersect) {
    return INTERSECTING;
  }
  
  return INSIDE;
}

} // aer
